#pragma once
#include "gtest/gtest.h"
// #include "TestData/TestAssistance/MatrixTools.hpp"
#include "SGFem/ElementCalculator/Factory/ElementCalculatorFactory.h"
#include "DataStructure/Input/Material/ThermalMaterial.h"
#include "../Tetra4ThermalCalculator.h"
#include "Utility/Algebra/Tools.h"


using SG::Algebra::Matrix;
using SG::DataStructure::Common::Real;
using SG::Algebra::calcTetraVolumn;
using namespace SG::DataStructure::FEM;
using namespace SG::FEMSolver::Element;

// ElementCalculatorFactory 是否正确创建单元计算类
// 将 ElementCalculatorFactory 的 Register和生成对象测试放置在具体单元类型计算中
TEST (ElementCalculatorFactoryTest, Tetra4ThermalElement)
{
    ElementCalculatorFactory::Register (ElementTypes::ELETYPE_Tetra4, Tetra4ThermalCalculator::Create);

    // Test
    auto CalculatorPtr = ElementCalculatorFactory::Create (ElementTypes::ELETYPE_Tetra4);

    // Target data
    auto tetra4Calctor = dynamic_cast<Tetra4ThermalCalculator*> (CalculatorPtr.get ());

    // Check
    ASSERT_TRUE (0 != tetra4Calctor);
}
extern std::shared_ptr<DBServiceFactory> DB_SERVICEFACTORY;

class Tetra4ThermalCalculatorTest : public ::testing::Test
{
public:

    virtual void SetUp() override
    {
        // 指定材料属性
        k = 1.0;
        points = SG::Algebra::PointArray(4);
        points[0].m_x = 0.0;  points[0].m_y = 0.0;  points[0].m_z = 40.0;                
        points[1].m_x = 20.0;  points[1].m_y = 0.0;  points[1].m_z = 0.0;
        points[2].m_x = 0.0;  points[2].m_y = 0.0;  points[2].m_z = 0.0;  
        points[3].m_x = 0.0;  points[3].m_y = 30.0;  points[3].m_z = 0.0;       
    }

protected:
    Real k;
    SG::Algebra::PointArray points; ///< 单元节点坐标
};


TEST_F (Tetra4ThermalCalculatorTest, ComputeStiffness)
{
    Tetra4ThermalCalculator elementCalc;
    elementCalc.Initialize(ELETYPE_Tetra4);

    Matrix Kel(4, 4);
    Matrix vertices(4,3);
    Real volumn;
    ThermalMaterial material;
    material.m_K = 1.0;
    for (std::size_t iNode = 0; iNode < 4; ++iNode)
    {
        vertices(iNode, 0) = points[iNode].m_x;
        vertices(iNode, 1) = points[iNode].m_y;
        vertices(iNode, 2) = points[iNode].m_z;
    }
    
    volumn = calcTetraVolumn(vertices);
    Real volumnTarget = 4000.0;
    ASSERT_TRUE(volumn == volumnTarget);

    elementCalc.ComputeStiffness(vertices, material, Kel);
    
    Matrix KelTarget(4, 4, {          
        2.5000000000000    ,  0.0000000000000    ,  -2.5000000000000    ,  0.0000000000000    ,
        0.0000000000000    ,  10.000000000000    ,  -10.000000000000    ,  0.0000000000000    ,
        -2.5000000000000   ,  -10.000000000000   ,  16.944444444444     ,  -4.4444444444444    ,
        0.0000000000000    ,  0.0000000000000    ,  -4.4444444444444    ,  4.4444444444444
         });
    
    ASSERT_TRUE(Kel == KelTarget);
}